#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
极速数据API彩票爬虫基类
"""

import requests
import time
import json
from datetime import datetime, date, timedelta
from typing import List, Dict, Any, Optional
from loguru import logger

from .base_spider import BaseLotterySpider
from ..config.settings import JISU_API_CONFIG, LOTTERY_TYPES, CRAWLER_CONFIG
from ..database import db_manager


class JisuLotterySpider(BaseLotterySpider):
    """极速数据API彩票爬虫基类"""
    
    def __init__(self, lottery_type: str):
        super().__init__(lottery_type)
        self.api_config = JISU_API_CONFIG
        self.lottery_config = LOTTERY_TYPES.get(lottery_type, {})
        self.caipiaoid = self.lottery_config.get('caipiaoid')
        self.daily_fetch_count = self.lottery_config.get('daily_fetch_count', 16)
        
        if not self.caipiaoid:
            raise ValueError(f"未找到彩票类型 {lottery_type} 的配置")
    
    def get_latest_period_from_db(self) -> Optional[str]:
        """从数据库获取最新期号"""
        try:
            sql = """
            SELECT period FROM lottery_results
            WHERE lottery_type = %s
            ORDER BY period DESC
            LIMIT 1
            """
            results = db_manager.execute_query(sql, (self.lottery_type,))
            result = results[0] if results else None
            return str(result['period']) if result else None
        except Exception as e:
            logger.error(f"获取最新期号失败: {e}")
            return None
    
    def get_earliest_period_from_db(self) -> Optional[str]:
        """从数据库获取最早期号"""
        try:
            sql = """
            SELECT period FROM lottery_results
            WHERE lottery_type = %s
            ORDER BY period ASC
            LIMIT 1
            """
            results = db_manager.execute_query(sql, (self.lottery_type,))
            result = results[0] if results else None
            return str(result['period']) if result else None
        except Exception as e:
            logger.error(f"获取最早期号失败: {e}")
            return None
    
    def calculate_start_period(self, latest_period: str) -> str:
        """计算起始期号（从最新期号往前推，用于抓取最新数据）
        
        Args:
            latest_period: 最新期号，格式如 '2025030'
            
        Returns:
            起始期号
        """
        try:
            # 解析期号：前4位是年份，后3位是期数
            year = int(latest_period[:4])
            period_num = int(latest_period[4:])
            
            # 计算起始期号（往前推 daily_fetch_count 期）
            start_period_num = period_num - self.daily_fetch_count + 1
            
            # 如果期号小于1，需要跨年处理
            if start_period_num < 1:
                # 简化处理：假设每年最多365期
                year -= 1
                start_period_num = 365 + start_period_num
            
            # 格式化期号
            start_period = f"{year}{start_period_num:03d}"
            return start_period
            
        except Exception as e:
            logger.error(f"计算起始期号失败: {e}")
            # 默认返回当前期号往前推16期
            return latest_period
    
    def calculate_history_start_period(self, earliest_period: str) -> str:
        """计算历史数据起始期号（从最早期号往前推，用于补充历史数据）
        
        Args:
            earliest_period: 最早期号，格式如 '2025030'
            
        Returns:
            历史数据起始期号
        """
        try:
            # 解析期号：前4位是年份，后3位是期数
            year = int(earliest_period[:4])
            period_num = int(earliest_period[4:])
            
            # 计算历史起始期号（往前推 daily_fetch_count 期）
            history_end_period_num = period_num - 1  # 最早期号的前一期
            history_start_period_num = history_end_period_num - self.daily_fetch_count + 1
            
            # 如果期号小于1，需要跨年处理
            if history_start_period_num < 1:
                # 简化处理：假设每年最多365期
                year -= 1
                history_start_period_num = 365 + history_start_period_num
            
            # 格式化期号
            history_start_period = f"{year}{history_start_period_num:03d}"
            return history_start_period
            
        except Exception as e:
            logger.error(f"计算历史起始期号失败: {e}")
            # 默认返回最早期号往前推1期
            return earliest_period
    
    def fetch_latest_lottery_data(self) -> Optional[Dict]:
        """获取最新一期彩票数据（使用query端点，节省API调用次数）
        
        Returns:
            API响应数据
        """
        url = f"{self.api_config['base_url']}/query"
        params = {
            'appkey': self.api_config['appkey'],
            'caipiaoid': self.caipiaoid
            # 不传issueno参数，默认获取最新一期
        }
        
        try:
            logger.info(f"请求极速数据API最新数据: {url}, 参数: {params}")
            response = self.session.get(
                url, 
                params=params, 
                timeout=self.api_config['timeout']
            )
            response.raise_for_status()
            
            data = response.json()
            if data.get('status') != 0:
                logger.error(f"API返回错误: {data.get('msg', '未知错误')}")
                return None
                
            return data.get('result', {})
            
        except requests.exceptions.RequestException as e:
            logger.error(f"请求API失败: {e}")
            return None
        except json.JSONDecodeError as e:
            logger.error(f"解析JSON失败: {e}")
            return None
    
    def fetch_latest_single_data(self) -> Optional[Dict]:
        """从query端点获取单条最新数据
        
        Returns:
            单条最新彩票数据，解析后的格式
        """
        url = f"{self.api_config['base_url']}/query"
        params = {
            'appkey': self.api_config['appkey'],
            'caipiaoid': self.caipiaoid
        }
        
        try:
            logger.info(f"请求极速数据API最新数据: {url}, 参数: {params}")
            response = self.session.get(
                url, 
                params=params, 
                timeout=self.api_config['timeout']
            )
            response.raise_for_status()
            
            data = response.json()
            if data.get('status') != 0:
                logger.error(f"API返回错误: {data.get('msg', '未知错误')}")
                return None
                
            result_data = data.get('result', {})
            if not result_data:
                logger.warning(f"API返回空结果")
                return None
            
            # 解析单条数据
            parsed_result = self.parse_single_result(result_data)
            if parsed_result:
                logger.info(f"成功解析最新数据: 期号 {parsed_result.get('period', 'N/A')}")
            
            return parsed_result
            
        except requests.exceptions.RequestException as e:
            logger.error(f"请求API失败: {e}")
            return None
        except json.JSONDecodeError as e:
            logger.error(f"解析JSON失败: {e}")
            return None

    def fetch_lottery_data(self, num: int = None, start: int = 0, issueno: str = None) -> Optional[Dict]:
        """获取彩票历史数据
        
        Args:
            num: 获取数量，默认使用配置的每日抓取数量
            start: 起始位置（偏移量，从0开始）- 当issueno为None时使用
            issueno: 期号，获取该期号之前的数据 - 优先使用
            
        Returns:
            API响应数据
        """
       
        if num is None:
            num = self.daily_fetch_count
            
        url = f"{self.api_config['base_url']}/history"
        params = {
            'appkey': self.api_config['appkey'],
            'caipiaoid': self.caipiaoid,
            'num': min(num, 20),  # API最大支持20条
        }
        
        # 优先使用issueno参数，如果没有则使用start偏移量
        if issueno:
            params['issueno'] = issueno
        else:
            params['start'] = start
        
        try:
            logger.debug(f"请求极速数据API历史数据: {url}, 参数: {params}")
            response = self.session.get(
                url, 
                params=params, 
                timeout=self.api_config['timeout']
            )
            response.raise_for_status()
            
            data = response.json()
            if data.get('status') != 0:
                logger.error(f"API返回错误: {data.get('msg', '未知错误')}")
                return None
                
            return data.get('result', {})
            
        except requests.exceptions.RequestException as e:
            logger.error(f"请求API失败: {e}")
            return None
        except json.JSONDecodeError as e:
            logger.error(f"解析JSON失败: {e}")
            return None
    
    def parse_lottery_data(self, data: Dict) -> List[Dict]:
        """解析彩票数据
        
        Args:
            data: API返回的数据
            
        Returns:
            解析后的彩票结果列表
        """
        results = []
        
        if 'list' not in data:
            logger.warning("API返回数据中没有list字段")
            return results
        
        for item in data['list']:
            try:
                result = self.parse_single_result(item)
                if result:
                    results.append(result)
            except Exception as e:
                logger.error(f"解析单条数据失败: {e}, 数据: {item}")
                continue
        
        return results
    
    def parse_single_result(self, item: Dict) -> Optional[Dict]:
        """解析单条彩票结果
        
        Args:
            item: 单条彩票数据
            
        Returns:
            解析后的彩票结果
        """

        try:
            # 期号 - 修复：先检查是否为 None，避免转换成字符串 'None'
            issueno = item.get('issueno', '')
            if issueno is None or issueno == '':
                logger.warning(f"期号为空或None，跳过该条数据: {item}")
                return None
            period = str(issueno).strip()
            if not period or period.lower() == 'none':
                logger.warning(f"期号无效: {period}，跳过该条数据")
                return None
            
            # 开奖号码 - 修复：先检查是否为 None
            number = item.get('number', '')
            if number is None or number == '':
                logger.warning(f"期号 {period} 开奖号码为空或None")
                return None
            numbers = str(number).strip()
            if not numbers or numbers.lower() == 'none':
                logger.warning(f"期号 {period} 开奖号码无效: {numbers}")
                return None
            
            # 数据验证：检查号码数量是否正确
            if self.lottery_type == 'pl3':
                # pl3应该只有3个号码
                number_list = numbers.split()
                if len(number_list) != 3:
                    logger.warning(f"pl3号码数量异常: {len(number_list)}个，期号: {period}，号码: {numbers}")
                    return None
            elif self.lottery_type == 'pl5':
                # pl5应该只有5个号码
                number_list = numbers.split()
                if len(number_list) != 5:
                    logger.warning(f"pl5号码数量异常: {len(number_list)}个，期号: {period}，号码: {numbers}")
                    return None
            
            # 参考号码（蓝球、后区号码等）- 修复：先检查是否为 None
            refernumber_val = item.get('refernumber', '')
            refernumber = str(refernumber_val).strip() if refernumber_val is not None else ''
            # 如果是字符串 'None'，置为空字符串
            if refernumber.lower() == 'none':
                refernumber = ''
            
            # 开奖日期 - 修复：先检查是否为 None
            opendate_val = item.get('opendate', '')
            if opendate_val and opendate_val is not None:
                opendate = str(opendate_val).strip()
                # 检查是否是字符串 'None'
                if opendate.lower() == 'none':
                    logger.warning(f"期号 {period} 开奖日期为None，跳过该条数据")
                    return None
                else:
                    # 支持多种日期格式
                    draw_date = None
                    date_formats = [
                        '%Y-%m-%d',              # 新数据格式: "2025-11-02"
                        '%Y-%m-%d %H:%M:%S',     # 旧数据格式: "2020-08-26 23:51:08"
                    ]

                    for fmt in date_formats:
                        try:
                            draw_date = datetime.strptime(opendate, fmt).date()
                            opendate = draw_date.strftime('%Y-%m-%d')
                            break
                        except ValueError:
                            continue

                    if draw_date is None:
                        logger.warning(f"期号 {period} 日期格式无法识别: {opendate}，跳过该条数据")
                        return None
            else:
                logger.warning(f"期号 {period} 开奖日期为空，跳过该条数据")
                return None
            
            # 销售额
            saleamount = item.get('saleamount', '')
            
            # 解析奖池金额
            pool_amount = None
            if 'totalmoney' in item:
                try:
                    pool_amount = float(item['totalmoney'])
                except (ValueError, TypeError):
                    logger.warning(f"奖池金额解析失败: {item.get('totalmoney')}")
            
            # 解析奖级信息
            prize_info = None
            if 'prize' in item:
                try:
                    # 直接保存为dict/list，让base_spider处理JSON序列化
                    prize_info = item['prize']
                except (TypeError, ValueError):
                    logger.warning(f"奖级信息解析失败: {item.get('prize')}")
            
            # 解析省份中奖情况（从content字段提取）
            province_info = None
            if 'content' in item and item['content']:
                province_info = self.parse_province_info(item['content'], period)
            
            # 组合开奖号码
            if refernumber:
                full_numbers = f"{numbers},{refernumber}"
            else:
                full_numbers = numbers
            
            result = {
                'period': period,
                'numbers': full_numbers,
                'draw_time': opendate,
                'lottery_type': self.lottery_type,
                'sale_amount': saleamount,
                'pool_amount': pool_amount,  # 添加奖池金额
                'prize_info': prize_info,    # 添加奖级信息
                'province_info': province_info  # 添加省份中奖信息
            }

            return result
            
        except Exception as e:
            logger.error(f"解析单条结果失败: {e}")
            return None
    
    def parse_province_info(self, content: str, period: str) -> Optional[List[Dict]]:
        """解析省份中奖信息
        
        Args:
            content: 包含省份中奖信息的文本内容
            period: 期号
            
        Returns:
            省份中奖信息列表
        """
        import re
        
        # 只处理支持省份详情的彩种
        if self.lottery_type in ['fc3d', 'pl3', 'pl5']:
            return None
        
        try:
            provinces = []
            
            # 使用正则表达式解析省份信息
            # 匹配模式：省份名称+数字+注
            pattern = r'([^，。\s]+?)(\d+)注'
            matches = re.findall(pattern, content)
            
            for match in matches:
                province_name = match[0].strip()
                winner_count = int(match[1])
                
                # 过滤掉一些非省份的匹配
                if len(province_name) > 10 or winner_count == 0:
                    continue
                
                provinces.append({
                    'province_name': province_name,
                    'winner_count': winner_count
                })
            
            if provinces:
                logger.info(f"解析到{self.lottery_type} {period}期 {len(provinces)}个省份的中奖信息")
            
            return provinces if provinces else None
            
        except Exception as e:
            logger.error(f"解析省份信息失败: {e}")
            return None
    
    def crawl_lottery_data(self, periods: int = None) -> List[Dict]:
        """爬取彩票数据
        
        Args:
            periods: 要爬取的期数，默认使用配置的每日抓取数量
            
        Returns:
            爬取到的彩票结果列表
        """
        if periods is None:
            periods = self.daily_fetch_count
        
        all_results = []
        fetched = 0

        # 使用偏移量从0开始，逐步递增
        offset = 0

        # 计算需要的批次数
        total_batches = (periods + 19) // 20  # 向上取整
        current_batch = 0

        while fetched < periods:
            current_batch += 1
            # 计算本次要获取的数量
            batch_size = min(20, periods - fetched)  # API最大支持20条
            
            # 显示进度
            logger.info(f"正在获取第 {current_batch}/{total_batches} 批数据 (已获取 {fetched}/{periods})")
            
            # 获取数据，使用偏移量
            data = self.fetch_lottery_data(num=batch_size, start=offset)
            if not data:
                logger.error("获取数据失败")
                break
            
            # 解析数据
            results = self.parse_lottery_data(data)
            if not results:
                logger.warning("没有解析到有效数据")
                break
            
            all_results.extend(results)
            fetched += len(results)
            offset += batch_size  # 偏移量递增
            
            # 如果返回的数据少于请求的数量，说明没有更多数据了
            if len(results) < batch_size:
                logger.info(f"API返回数据少于请求数量，可能已到达最早数据")
                break
            
            # 避免请求过快，使用配置的延迟时间
            time.sleep(CRAWLER_CONFIG.get('request_delay', 0.2))
        
        logger.info(f"共爬取到 {len(all_results)} 条 {self.lottery_type} 数据")
        return all_results
    
    def save_lottery_results(self, results: List[Dict]) -> int:
        """保存彩票结果到数据库
        
        Args:
            results: 彩票结果列表
            
        Returns:
            成功保存的数量
        """
        if not results:
            return 0
        
        saved_count = 0
        
     
        for result in results:
            try:
                # 解析开奖日期
                draw_date_str = result.get('draw_time', '')
                if draw_date_str:
                    try:
                        draw_date = datetime.strptime(draw_date_str, '%Y-%m-%d').date()
                    except ValueError:
                        draw_date = datetime.now().date()
                else:
                    draw_date = datetime.now().date()
                
                # 解析号码
                numbers_str = result.get('numbers', '')
                if numbers_str:
                    all_numbers = numbers_str.split(',')
                else:
                    all_numbers = []
                
                # 解析销售额
                sales_amount = result.get('sale_amount')
                if sales_amount and isinstance(sales_amount, str):
                    try:
                        sales_amount = float(sales_amount)
                    except ValueError:
                        sales_amount = None
                
                # 解析奖池金额
                pool_amount = result.get('pool_amount')
                if pool_amount and isinstance(pool_amount, str):
                    try:
                        pool_amount = float(pool_amount)
                    except ValueError:
                        pool_amount = None
                
                # 获取奖级信息（已经是dict/list格式）
                prize_info = result.get('prize_info')
                
                # 调用基类的保存方法
                success = self.save_lottery_result(
                    period=result['period'],
                    draw_date=draw_date,
                    all_numbers=all_numbers,
                    sales_amount=sales_amount,
                    pool_amount=pool_amount,  # 添加奖池金额
                    prize_info=prize_info     # 添加奖级信息
                )
                

                
                if success:
                    saved_count += 1
                    logger.info(f"保存 {self.lottery_type} {result['period']} 期数据成功")
                    
                    # 保存省份中奖信息
                    province_info = result.get('province_info')
                    if province_info:
                        self.save_province_details(result['period'], draw_date, province_info)
                else:
                    logger.warning(f"保存 {self.lottery_type} {result['period']} 期数据失败")
            except Exception as e:
                logger.error(f"保存数据时发生错误: {e}")
                continue
        
        logger.info(f"成功保存 {saved_count}/{len(results)} 条 {self.lottery_type} 数据")
        return saved_count
    
    def save_province_details(self, period: str, draw_date, province_info: List[Dict]):
        """保存省份中奖详情
        
        Args:
            period: 期号
            draw_date: 开奖日期
            province_info: 省份中奖信息列表
        """
        try:
            for province in province_info:
                self.save_province_prize(
                    period=period,
                    draw_date=draw_date,
                    province_name=province['province_name'],
                    first_prize_winners=province['winner_count']
                )
            
            logger.info(f"保存 {self.lottery_type} {period} 期 {len(province_info)} 个省份中奖信息成功")
            
        except Exception as e:
            logger.error(f"保存省份中奖信息失败: {e}")
    
    def crawl_latest(self, count: int = None) -> int:
        """爬取最新开奖数据
        
        Args:
            count: 爬取期数，如果为1则使用query端点获取单条最新数据，否则使用history端点
            
        Returns:
            成功保存的数据条数
        """
        if count is None:
            count = self.daily_fetch_count
            
        logger.info(f"开始爬取 {self.lottery_config['name']} 最新 {count} 期数据")
        
     
        try:
            if count == 1:
                # 获取单条最新数据，使用query端点
                logger.info(f"使用query端点获取 {self.lottery_config['name']} 最新单条数据")
                result = self.fetch_latest_single_data()
                if not result:
                    logger.warning(f"没有爬取到 {self.lottery_config['name']} 最新数据")
                    return 0
                
                # 保存数据
                saved_count = self.save_lottery_results([result])
                logger.info(f"{self.lottery_config['name']} 最新数据爬取完成，保存 {saved_count} 条")
                return saved_count
            else:
                # 获取多条数据，使用history端点
                logger.info(f"使用history端点获取 {self.lottery_config['name']} 最新 {count} 期数据")
                results = self.crawl_lottery_data(count)
                
                if not results:
                    logger.warning(f"没有爬取到 {self.lottery_config['name']} 数据")
                    return 0
                
                # 保存数据
                saved_count = self.save_lottery_results(results)
                logger.info(f"{self.lottery_config['name']} 最新数据爬取完成，保存 {saved_count} 条")
                return saved_count
            
        except Exception as e:
            logger.error(f"爬取 {self.lottery_config['name']} 最新数据失败: {e}")
            return 0
    
    def crawl_history_smart(self, count: int = None) -> int:
        
        """智能抓取历史数据（从最早期号往前补充）
        
        使用issueno参数，每次传入数据库最小期号，API返回该期号之前的数据
        
        Args:
            count: 抓取期数，默认使用配置的每日抓取数量
            
        Returns:
            成功保存的数据条数
        """

        if count is None:
            count = self.daily_fetch_count
            
        logger.info(f"开始智能抓取 {self.lottery_config['name']} 历史数据 {count} 期")
        
        try:
            # 获取数据库中的最早期号
            earliest_period = self.get_earliest_period_from_db()
            
            if not earliest_period:
                logger.info(f"数据库中没有 {self.lottery_config['name']} 数据，使用常规最新数据抓取")
                return self.crawl_latest(count)
            
            logger.info(f"数据库中最早期号: {earliest_period}，将使用该期号获取更早的历史数据")
            
            # 统计变量
            total_saved = 0  # 总保存数
            current_earliest = earliest_period  # 当前最早期号
            
            # 计算需要的批次数
            total_batches = (count + 19) // 20
            current_batch = 0
            
            # 分批保存阈值（每100条保存一次，避免内存累积）
            BATCH_SAVE_THRESHOLD = 100
            batch_buffer = []
            
            while total_saved < count:
                current_batch += 1
                batch_size = min(20, count - total_saved)
                
                logger.info(f"正在获取第 {current_batch}/{total_batches} 批历史数据 (已保存: {total_saved}/{count}, 当前最早期号: {current_earliest})")
                
                # 使用issueno参数获取该期号之前的数据
                data = self.fetch_lottery_data(num=batch_size, issueno=current_earliest)
                if not data:
                    logger.error("获取数据失败")
                    break
                
                # 解析数据
                results = self.parse_lottery_data(data)
                if not results:
                    logger.warning("没有解析到有效数据")
                    break
                
                # 检查返回的数据数量
                actual_returned = len(results)
                if actual_returned == 0:
                    logger.info(f"API没有返回数据，已到达最早数据")
                    break
                
                logger.info(f"✓ 本批次: API返回 {actual_returned} 条数据")
                
                # 添加到缓冲区
                batch_buffer.extend(results)
                
                # 当缓冲区达到阈值时，分批保存（防止内存累积）
                if len(batch_buffer) >= BATCH_SAVE_THRESHOLD:
                    saved = self.save_lottery_results(batch_buffer)
                    total_saved += saved
                    logger.info(f"💾 分批保存 {saved} 条数据到数据库（累计: {total_saved}）")
                    
                    # 更新当前最早期号为缓冲区中的最小期号
                    if batch_buffer:
                        periods = [str(r.get('period')) for r in batch_buffer if r.get('period')]
                        if periods:
                            # 按整数比较期号，获取最小的
                            current_earliest = min(periods, key=lambda x: int(x))
                            logger.info(f"   更新最早期号为: {current_earliest}")
                    
                    batch_buffer.clear()  # 清空缓冲区，释放内存
                else:
                    # 即使不保存，也要更新最早期号
                    periods = [str(r.get('period')) for r in results if r.get('period')]
                    if periods:
                        new_earliest = min(periods, key=lambda x: int(x))
                        # 按整数比较期号
                        logger.debug(f"   比较期号: new_earliest={new_earliest} ({int(new_earliest)}), current_earliest={current_earliest} ({int(current_earliest)})")
                        if int(new_earliest) < int(current_earliest):
                            current_earliest = new_earliest
                            logger.debug(f"   已更新最早期号为: {current_earliest}")
                        else:
                            logger.warning(f"   期号未更新：{new_earliest} >= {current_earliest}，可能是数据库期号格式错误")
                
                # 显式删除不再需要的大对象，帮助垃圾回收
                del results
                
                # 如果返回的数据少于请求的数量，说明没有更多数据了
                if actual_returned < batch_size:
                    logger.info(f"API返回数据少于请求数量({actual_returned}/{batch_size})，已到达最早数据")
                    break
                
                # 避免请求过快
                time.sleep(CRAWLER_CONFIG.get('request_delay', 0.2))
            
            # 保存剩余的数据
            if batch_buffer:
                saved = self.save_lottery_results(batch_buffer)
                total_saved += saved
                logger.info(f"💾 保存剩余 {saved} 条数据到数据库")
                batch_buffer.clear()
            
            if total_saved == 0:
                logger.info(f"没有找到比 {earliest_period} 更早的历史数据")
                return 0
            
            logger.info(f"📊 {self.lottery_config['name']} 历史数据抓取完成")
            logger.info(f"   成功入库: {total_saved} 条")
            logger.info(f"   新的最早期号: {current_earliest}")
            return total_saved
            
        except Exception as e:
            logger.error(f"智能抓取 {self.lottery_config['name']} 历史数据失败: {e}")
            import traceback
            logger.error(traceback.format_exc())
            return 0
    
    def crawl_history(self, start_period: str = None, end_period: str = None) -> bool:
        """爬取历史开奖数据
        
        Args:
            start_period: 开始期号
            end_period: 结束期号
            
        Returns:
            是否成功
        """
        logger.info(f"开始爬取 {self.lottery_config['name']} 历史数据")
        
       
        try:
            # 对于极速数据API，历史数据爬取使用默认的批量获取方式
            # 因为API不支持按期号范围查询，所以获取最新的一批数据
            results = self.crawl_lottery_data()
            
            if not results:
                logger.warning(f"没有爬取到 {self.lottery_config['name']} 历史数据")
                return False
            
            # 保存数据
            saved_count = self.save_lottery_results(results)
            logger.info(f"{self.lottery_config['name']} 历史数据爬取完成，保存 {saved_count} 条")
            return saved_count > 0
            
        except Exception as e:
            logger.error(f"爬取 {self.lottery_config['name']} 历史数据失败: {e}")
            return False
    
    def parse_lottery_data(self, response_data: Any) -> List[Dict]:
        """解析彩票数据（实现抽象方法）
        
        Args:
            response_data: API响应数据
            
        Returns:
            解析后的彩票结果列表
        """
        if isinstance(response_data, dict):
            # 调用内部的解析方法
            results = []
            
            if 'list' not in response_data:
                logger.warning("API返回数据中没有list字段")
                return results
            
            for item in response_data['list']:
                try:
                    result = self.parse_single_result(item)
                    if result:
                        results.append(result)
                except Exception as e:
                    logger.error(f"解析单条数据失败: {e}, 数据: {item}")
                    continue
            
            return results
        else:
            logger.warning("响应数据格式不正确")
            return []
    
    def run(self, mode: str = 'latest', **kwargs) -> int:
        """运行爬虫
        
        Args:
            mode: 运行模式 ('latest' 或 'history')
            **kwargs: 其他参数
            
        Returns:
            成功保存的数据条数
        """
        logger.info(f"开始运行 {self.lottery_config['name']} 爬虫，模式: {mode}")
        try:
            if mode == 'latest':
                count = kwargs.get('count', self.daily_fetch_count)
                return self.crawl_latest(count)
            elif mode == 'history':
             
                start_period = kwargs.get('start_period')
                end_period = kwargs.get('end_period')
                success = self.crawl_history(start_period, end_period)
                return 1 if success else 0
            else:
                logger.error(f"不支持的运行模式: {mode}")
                return 0
                
        except Exception as e:
            logger.error(f"运行 {self.lottery_config['name']} 爬虫失败: {e}")
            return 0